package com.gitee.wsl.ext.collection

inline fun <S, T > Iterable<S>.mapReduce(operation: (S, S) -> T ): List<T> {
    val iterator = this.iterator()
    if (!iterator.hasNext()) return emptyList()
    val retList= mutableListOf<T>()
    var accumulator  = iterator.next()
    var next: S
    while (iterator.hasNext()) {
        next = iterator.next()
        retList.add(operation(accumulator, next))
        accumulator = next
    }
    return retList
}

/**
 * Returns an iterator yielding the results of applying the given [transform] function
 * to each element in the original iterator.
 */
fun <T, R> Iterator<T>.map(transform: (T) -> R): Iterator<R> =
    object : Iterator<R> {
        override fun hasNext(): Boolean = this@map.hasNext()
        override fun next(): R = transform(this@map.next())
    }

/**
 * Returns an iterator that yield ranges with each element ranging from the `predecessor+1..current-1`
 * and the first element starting with the specified [start].
 */
fun Iterator<Int>.mapToRanges(start: Int = 0): Iterator<IntRange> {
    var prev = start
    return map { prev until it.also { prev = it } }
}


fun <T, R: Any> Iterable<T>.partitionMap(f: (T) -> Pair<R, Boolean>): Pair<List<R>, List<R>> {
    val first = mutableListOf<R>()
    val second = mutableListOf<R>()
    for (element in this) {
        val (value, pred) = f(element)
        val dst = if (pred) first else second
        dst.add(value)
    }
    return Pair(first, second)
}

/**
 * Creates a map from the elements of this iterable using the provided key and value functions.
 *
 * @param map the map to populate with the elements of this iterable.
 * @param key a function that maps an element to a key.
 * @param value a function that maps an element to a value.
 * @return the populated map.
 */
inline fun <O, K, V> Iterable<O>.toMapTo(
    map: MutableMap<K, V>,
    key: (O) -> K,
    value: (O) -> V,
): Map<K, V> {
    for (element in this) {
        map[key(element)] = value(element)
    }
    return map
}


inline fun <O, K, V> Iterable<O>.toMap(
    key: (O) -> K,
    value: (O) -> V,
): Map<K, V> {
    return toMapTo(mutableMapOf(), key, value)
}

inline fun <T, R> Iterable<T>.flatMapToMutableList(transform: (T) -> Iterable<R>): MutableList<R> =
    flatMapTo(mutableListOf(), transform)

//inline fun <T, R> Iterable<T>.mapToMutableList(transform: (T) -> R): MutableList<R> = mapTo(mutableListOf(), transform)

inline fun <T, R> Iterable<T>.mapToMutableList(transform: (T) -> R): MutableList<R> =
    mapTo(ArrayList(collectionSizeOrDefault(10)), transform)

inline fun <T, R> Iterable<T>.mapToSet(transform: (T) -> R): Set<R> =
    mapTo(HashSet(mapCapacity(collectionSizeOrDefault(10))), transform)

inline fun <T, R : Any> Iterable<T>.mapNotNullToSet(transform: (T) -> R?): Set<R> =
    mapNotNullTo(HashSet(mapCapacity(collectionSizeOrDefault(10))), transform)